#ifndef __DIST_CAPVALIDATOR_H__
#define __DIST_CAPVALIDATOR_H__

#include "GAframework.hpp"
#include "CaP_Validator.hpp"
#include <vector>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <math.h>
#include "DistCaPProtocol.hpp"

using namespace std;

/** \class CaPValidatorException
 *  \brief Eccezioni lanciate dalla classe CaPValidator. Contiene solo un messaggio di errore.
 */
class DistCaPValidatorException : public ValidatorException
{
    public:
    DistCaPValidatorException(char *mess) : ValidatorException(mess) {};
};

/** \class DistCaPValidator
 */
class DistCaPValidator : public Validator
{
public:
	enum client_status {
		DIST_CAP_CS_RUN,	//Running
		DIST_CAP_CS_END		//Terminazione
	};

	typedef struct
	{
		pthread_t thread_id;
		enum client_status myStatus;
		int eval_from;
		int eval_len;
		int id;
		int userSocket;
		DistCaPProtocol *proto;
		DistCaPValidator *Master;
		unsigned int *evaluations;
		float eval_time;
		float eval_per_sec;
		pthread_mutex_t	M;
		pthread_mutex_t	U;
	} TV_entry;
private:

	unsigned int max_score;

	float my_eval_time;
	float my_eval_per_sec;
	int my_eval_len;

	CaP_Validator *myValidator;

	vector<TV_entry*> UserThreads;

	TV_entry *StartConnection(string &IP,int PORT) throw(DistCaPValidatorException);
	void StartThread(TV_entry *tve) throw(DistCaPValidatorException);

	//DistCaPProtocol *proto;

	void update_load_distribution(int pop_len);

public:
	enum error_hand_type{
        ERR_IGNORE,     //!< Ignora gli errori quando possibile
        ERR_HALT        //!< Lancia CaPValidatorException a fronte di qualsiasi errore
    };

	Popolazione *local_pop;

    /** Legge i settings ed effettua le inizializzazioni necessarie
     *
     *  I parametri necessari per il costruttore sono:
     *
     *
     *  \param[in] settings Contiene tutti i parametri necessari per l'inizializzazione
     *  \param[in] eht Specifica il comportamento a fronte di un errore nella lettura dei parametri
     */
    DistCaPValidator(GAmodSettings &settings,error_hand_type eht = ERR_HALT) throw(DistCaPValidatorException);

    ~DistCaPValidator();

    unsigned int valuta_pop(Popolazione *pop,stat_generation sg=Validator::STAT_ALL) throw(DistCaPValidatorException) ;

    /** Restituisce le statistiche del valutatore
     *
     *  \param[out] settings Contenitore delle statistiche da ritornare
     */
    int getValutatorStats(GAmodSettings &settings) throw(DistCaPValidatorException) {return 0;};

    //! Ritorna il massimo punteggio ottenibile
    unsigned int getMaxScore() {return myValidator->getMaxScore();};

	unsigned int snapIndividuo(Individuo &Ind,char *path) throw(DistCaPValidatorException);
	unsigned int print_single_run(Individuo &Ind, int *map, int *food, char *path) throw(DistCaPValidatorException);

    //TODO: CaPValidator::getValutatorStats
};

#endif


